import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { BokehPass } from 'three/addons/postprocessing/BokehPass.js';
import { GLTF, GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
/**
 * gltf加载器
 */
let gltfLoader: GLTFLoader | null = null;
/**
 * dracoLoader
 */
let dracoLoader: DRACOLoader | null = null;

/**
 * 获取gltfloader
 * @returns
 */
export const getGltfLoader = () => {
  if (!gltfLoader) {
    gltfLoader = new GLTFLoader();
    dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath('/draco/');
    gltfLoader.setDRACOLoader(dracoLoader);
  }
  return gltfLoader;
};

/**
 * 销毁gltfloader
 */
export const disposeGltfLoader = () => {
  if (gltfLoader) {
    gltfLoader = null;
    dracoLoader = null;
  }
};

export const getScene = () => {
  return new THREE.Scene();
};

export const getCamera = (width: number, height: number) => {
  const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 300);
  camera.position.z = 10;
  camera.position.x = 0;
  camera.position.y = 10;
  return camera;
};

export const getFlyCamera = (width: number, height: number) => {
  const camera = new THREE.PerspectiveCamera(45, width / height, 1, 500);
  camera.position.z = 10;
  camera.position.x = 0;
  camera.position.y = 0;
  camera.lookAt(new THREE.Vector3(0, 0, 0));
  return camera;
};

export const getRenderer = (width: number, height: number) => {
  const renderer = new THREE.WebGLRenderer({
    antialias: true,
    powerPreference: 'high-performance',
    logarithmicDepthBuffer: true,
  });
  // window.devicePixelRatio
  renderer.setPixelRatio(1);
  renderer.setSize(width, height);
  // renderer.shadowMap.enabled = true; // 启用阴影映射
  // renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  // renderer.setClearColor(new THREE.Color(0x000000), 1);
  return renderer;
};

export const getAmbientLight = () => {
  return new THREE.AmbientLight(new THREE.Color(0xffffff), 3);
};

/**
 * 获取方向光
 * @returns
 */
export const getDirectionalLight = () => {
  const directionalLight = new THREE.DirectionalLight(0xffffff, 4);
  // directionalLight.position.set(10, 10, 0).normalize();
  // directionalLight.castShadow = true; // 允许光源投射阴影

  // // 配置阴影相机
  // directionalLight.shadow.mapSize.width = 1024;
  // directionalLight.shadow.mapSize.height = 1024;
  // directionalLight.shadow.camera.near = 0.5;
  // directionalLight.shadow.camera.far = 500;
  // directionalLight.shadow.camera.left = -50;
  // directionalLight.shadow.camera.right = 50;
  // directionalLight.shadow.camera.top = 50;
  // directionalLight.shadow.camera.bottom = -50;
  return directionalLight;
};

export const getFog = () => {
  // return new THREE.Fog(new THREE.Color('rgb(15,21,50)'), 10, 15);
  return new THREE.FogExp2('#e2f3f6', 0.045);
};

export const getStats = () => {
  return new Stats();
  // sceneContainerRef.value!.appendChild(stats.dom);
};

export const getOrbitControls = (camera: THREE.Camera, el: HTMLElement) => {
  const orbitControls = new OrbitControls(camera, el);
  orbitControls.listenToKeyEvents(window); // optional
  //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)
  orbitControls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
  orbitControls.dampingFactor = 0.05;
  orbitControls.screenSpacePanning = false;
  orbitControls.minDistance = 1;
  orbitControls.maxDistance = 500;
  orbitControls.maxPolarAngle = Math.PI / 2;

  return orbitControls;
};

/**
 * 获取材质加载器
 * @returns
 */
export const getTextareaLoader = () => {
  return new THREE.TextureLoader();
};

export const getBokehPass = (scene: THREE.Scene, camera: THREE.Camera) => {
  return new BokehPass(scene, camera, {
    focus: 2,
    aperture: 0.000008,
    maxblur: 3,
  });
};

export const getPlane = () => {
  const planeGeometry = new THREE.PlaneGeometry(100, 100);
  const planeMaterial = new THREE.MeshStandardMaterial({
    color: new THREE.Color('#0f7900'),
    side: THREE.FrontSide,
  });
  const plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -Math.PI / 2;
  plane.position.y = -0.2;
  return plane;
};

interface LoadGltfParams {
  modelPath: string;
  onProgress?: (loadProgress: number, xhr: ProgressEvent<EventTarget>) => void;
}

/**
 * 加载gltf
 * @param {LoadGltfParams} data
 * @param {string} data.modelPath 模型路径
 * @param {function} [data.onProgress] 加载进度回调函数，参数为当前进度百分比和xhr对象
 * @returns
 */
export const loadGltf = (data: LoadGltfParams): Promise<GLTF> => {
  const { modelPath, onProgress } = data;
  const gltfLoader = getGltfLoader();
  return new Promise((resolve, reject) => {
    gltfLoader.load(
      modelPath,
      (gltf) => {
        resolve(gltf);
      },
      (xhr) => {
        const loadProgress = (xhr.loaded / xhr.total) * 100;
        typeof onProgress === 'function' && onProgress(loadProgress, xhr);
      },
      (error) => {
        reject(error);
      },
    );
  });
};

/**
 * 获取地面材质贴图
 * @param textareaLoader
 * @returns
 */
export const getPlaneTextarea = (textareaLoader: THREE.TextureLoader) => {
  const planeTextarea = textareaLoader.load('/model/bg/images/AS2_Grass_01.jpg');
  planeTextarea.wrapS = THREE.RepeatWrapping;
  planeTextarea.wrapT = THREE.RepeatWrapping;
  planeTextarea.repeat.set(50, 50);
  // plane.material.map = planeTextarea;
  return planeTextarea;
};

interface LoadGltfAndCreateInstanceMeshWithMatrixWorldParams {
  modelPath: string;
  matrixWorldArray: number[][];
}
/**
 * 加载gltf模型，并创建实例网格，使用矩阵世界
 * @param {LoadGltfAndCreateInstanceMeshWithMatrixWorldParams} data
 * @param {string} data.modelPath 模型路径
 * @param {number[][]} data.matrixWorldArray 矩阵世界数组
 * @returns
 */
export const loadGltfAndCreateInstanceMeshWithMatrixWorld = async (
  data: LoadGltfAndCreateInstanceMeshWithMatrixWorldParams,
): Promise<THREE.InstancedMesh | null> => {
  const { modelPath, matrixWorldArray } = data;
  return loadGltf({
    modelPath,
  }).then((gltf) => {
    const models = gltf.scene;
    const mesh = models.isGroup ? models.children[0] : models;
    const geometry = mesh.geometry;
    const material = mesh.material;
    const instancedMesh = new THREE.InstancedMesh(geometry, material, matrixWorldArray.length);
    instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // 动态更新矩阵
    matrixWorldArray.forEach((item, index) => {
      // 创建一个新的 THREE.Matrix4 对象
      const matrixWorld = new THREE.Matrix4();
      // 从数组设置矩阵元素
      matrixWorld.fromArray(item);
      instancedMesh.setMatrixAt(index, matrixWorld);
      instancedMesh.instanceMatrix.needsUpdate = true;
    });
    return instancedMesh;
  });
};
